# !/usr/bin/env python
 # _*_ coding: utf-8 _*_
 # @Time : 2022/6/21 14:17
# @Author :
# @Version：V 0.1
 # @File : oauth_user.py
import time
import json
import hmac
import urllib
from urllib.parse import parse_qs, urlencode
import base64
import requests
from flask import Blueprint,current_app
from flask_restful import Api,Resource,reqparse
from werkzeug.security import check_password_hash
from common.utils.my_output_json import custom_output_json
from common.utils.jwt_utils import _generate_token
from common.models import db
from common.models.users import OAuthUserModel,UserModels

oauth_user_bp = Blueprint('oauth_user',__name__,url_prefix='/oauth')
# 创建蓝图的主入口
api = Api(oauth_user_bp)


# 统一后端返回给前端的数据结构
@api.representation('application/json')
def output_json(data, code,headers=None):
    resp = custom_output_json(data, code)
    return resp


class DingDingResource(Resource):
    def get_dingding_user(self,code):
        """获取扫码登录的用户信息"""
        # 2. 构建三个参数的值
        appid = current_app.config.get('DINGDING_APP_ID')
        appSecret = current_app.config.get('DINGDING_APP_SECRET')
        timestamp = str(int(time.time() * 1000))
        # .digest()获取hash对象的值
        signature = base64.b64encode(
            hmac.new(appSecret.encode('utf-8'), timestamp.encode('utf-8'), digestmod="sha256").digest())

        base_url = "https://oapi.dingtalk.com/sns/getuserinfo_bycode?signature="
        # 拼接url
        url = base_url + urllib.parse.quote(signature.decode('utf-8')) + "&timestamp="+timestamp + "&accessKey=" + appid
        data = json.dumps({'tmp_auth_code': code})
        try:
            resp = requests.post(url, data, headers={'Content-Type': 'application/json'})
            print("resp>>>", resp.json())
        except Exception as e:
            # 根据code 获取用户信息失败
            return {'code': 500, "message": 'post 获取钉钉用户信息失败'}
        # 获取用户信息
        user_info = resp.json()
        if user_info['errcode'] != 0:
            # 获取当前登录的而用户信息失败
            return {'code': 500, "message": '根据code获取钉钉用户信息失败'}
        # 把用户信息转换成dict
        user_info_dict = user_info['user_info']
        return user_info_dict

    def get(self):
        """
        1.获取code值
        2. 构建accessKey(应用的AppKey)
         timestamp，(当前的时间戳，是单位毫秒)
         signature:(appSecret计算出来的签名值)
         三个参数的值
        3. 发起请求：
        post https://oapi.dingtalk.com/sns/getuserinfo_bycode?accessKey=ACCESS_KEY&timestamp=TIMESTAMP&signature=SIGNATURE
        :return: userInfo
        """
        parser = reqparse.RequestParser()
        parser.add_argument('code')
        args = parser.parse_args()
        # 1.获取code值
        code = args.get('code')
        # 发起请求，获取当前登录的用户信息
        user_info = self.get_dingding_user(code)
        # 根据钉钉的用户信息获取钉钉的openid
        openid = user_info['openid']
        print('openid_____>', openid)
        # 获取openid 成功， 从oauth_user表查看当前钉钉用户是否和网站的用户绑定过
        oauth_user = OAuthUserModel.query.filter_by(oauth_id=openid,oauth_type='dingding').first()
        # 存在，说明绑定过
        if oauth_user:
            print("oauth_user>>>", oauth_user)
            # 获取绑定的用户信息
            user = UserModels.query.filter_by(uid=oauth_user.user).first()
            # TODO 添加token
            return {'code': 200, "account": user.account, 'uid': user.uid}
        # 不存在没绑定
        else:
            return {"message": "没有绑定用户，请先绑定", 'uid': openid}

class DingdingBindUser(Resource):
    def post(self):
        """绑定用户"""
        # 思路分析：
        """
        1. 获取用户信息：用户名， 密码， uid
        2. 判断用户是否在数据库存在：
            1. 存在
                校验密码
                直接绑定
            2. 不存在：
                先去注册
        """
        parser = reqparse.RequestParser()
        parser.add_argument('account')
        parser.add_argument('password')
        parser.add_argument('unid')
        args = parser.parse_args()
        account = args.get('account')
        pwd = args.get('password')
        unid = args.get('unid')
        # 判断用户是否在数据库存在
        user = UserModels.query.filter_by(account=account).first()
        if not user:
            #此时用户不存在
            return {'message':"用户未注册请先注册","code":400}
        # 用户存在
        else:
            rest = check_password_hash(user.password, pwd)
            if not rest:
                #密码错误
                return {'message':"密码错误","code":400}
            else:
                user_ = OAuthUserModel(oauth_id=unid,user=user.uid,oauth_type="dingding")
                db.session.add(user_)
                db.session.commit()
                # TODO 添加token
                data_ = {
                    'account':user.account,
                    'token':'',
                    'uid':user.uid
                }
                return {"message":'绑定成功','code':200, "data":data_}



class WeiboResource(Resource):
    def get(self):
        """根据code 获取微博用户信息"""
        parser = reqparse.RequestParser()
        parser.add_argument('code')
        args = parser.parse_args()
        # 1.获取code值
        code = args.get('code')
        # 构造参数获取weibo的用户信息

        base_url = 'https://api.weibo.com/oauth2/access_token'
        data_ = {
            "client_id":"2775107052",
            "client_secret" : "718b38b04fc387700cc1595b30875b19",
            "grant_type" : code
        }
        resp = requests.post(base_url,data=json.dumps(data_))
        print("resp=========>",resp.json())

        # 获取唯一的凭证
        access_token = resp.json()['access_token']
        oauth_uer = OAuthUserModel.query.filter_by(oauth_id=access_token, oauth_type='weibo').first()
        if oauth_uer:
            # 说明已经绑定
            user = UserModels.query.filter_by(uid=oauth_uer.user).first()
            data = {
                'uid':user.uid,
                'username':user.account
            }
            # 绑定后也是登录成功, 所以要有token值
            token, refresh_token = _generate_token(payload=data)
            return {'message':"登录成功","account": user.account, 'uid': user.uid,'token':token}
        else:
            # 没有绑定
            return {"message":"没有绑定请先绑定网站账号",'code':401, "uid":access_token}

api.add_resource(DingDingResource, '/dingding')
api.add_resource(DingdingBindUser,'/dingding/bind')
api.add_resource(WeiboResource,'/weibo')

